home *** CD-ROM | disk | FTP | other *** search
- /* strings.c Copyright(1988) Dan Heller */
-
- #include "mush.h"
-
- /*
- * reverse a string. Useful for uucp-style address comparisons.
- */
- char *
- reverse(s)
- char s[];
- {
- int n = strlen(s), m;
- char c;
-
- if (n < 1)
- return 0;
- if (n & 1)
- n = n/2 + 1, m = n - 2;
- else
- n /= 2, m = n - 1;
- for ( ; m >= 0; m--, n++)
- c = s[n], s[n] = s[m], s[m] = c;
- return s;
- }
-
- /*
- * lose the newline character, trailing whitespace, and return the end of p
- * test for '\n' separately since some _ctype_[] arrays may not have the
- * _S bit set for the newline character. see <ctype.h> for more info.
- */
- char *
- no_newln(p)
- register char *p;
- {
- register char *p2 = p + strlen(p); /* point it to the null terminator */
-
- while (p2 > p && *--p2 == '\n' || isspace(*p2))
- *p2 = 0; /* get rid of newline and trailing spaces */
- return p2;
- }
-
- /* find any character in s1 that's in s2; return pointer to char in s1. */
- char *
- any(s1, s2)
- register char *s1, *s2;
- {
- register char *p;
- if (!s1 || !*s1 || !s2 || !*s2)
- return NULL;
- for( ; *s1; s1++) {
- for(p = s2; *p; p++)
- if (*p == *s1)
- return s1;
- }
- return NULL;
- }
-
- /* check two lists of strings each of which contain substrings.
- * Each substring is delimited by any char in "delimiters"
- * return true if any elements in list1 are on list2.
- * thus:
- * string1 = "foo, bar, baz"
- * string2 = "foobar, baz, etc"
- * delimiters = ", \t"
- * example returns 1 because "baz" exists in both lists
- * NOTE: case is ignored.
- */
- chk_two_lists(list1, list2, delimiters)
- register char *list1, *list2, *delimiters;
- {
- register char *p, c;
- register int found = 0;
-
- if (!list1 || !list2)
- return 0;
-
- if (p = any(list1, delimiters)) {
- if (p > list1) {
- c = *p; *p = 0;
- /* Check list2 against the first word of list1.
- * Swap places of list2 and list1 to step through list2.
- */
- found = chk_two_lists(list2, list1, delimiters);
- *p = c;
- }
- if (found)
- return 1;
- for (p++; *p && index(delimiters, *p); p++)
- ;
- if (!*p)
- return 0;
- } else if (!any(list2, delimiters))
- /* Do the trivial case of single words */
- return !lcase_strncmp(list1, list2, -1);
- else
- p = list1;
-
- /* Either only list2 has delims or the first word of list1
- * did not match anything in list2. Check list2 against the
- * rest of list1. This could be more efficient by using a
- * different function to avoid repeating the any() calls.
- */
- return chk_two_lists(list2, p, delimiters);
- }
-
- bzero(addr, size)
- register char *addr;
- register int size;
- {
- while (size-- > 0)
- addr[size] = 0;
- }
-
- /* do an atoi() on the string passed and return in "val" the decimal value.
- * the function returns a pointer to the location in the string that is not
- * a digit.
- */
- char *
- my_atoi(p, val)
- register char *p;
- register int *val;
- {
- int positive = 1;
-
- if (!p)
- return NULL;
- *val = 0;
- if (*p == '-')
- positive = -1, p++;
- while (isdigit(*p))
- *val = (*val) * 10 + *p++ - '0';
- *val *= positive;
- return p;
- }
-
- /* strcmp ignoring case */
- lcase_strncmp(str1, str2, n)
- register char *str1, *str2;
- {
- while (*str1 && *str2 && --n != 0)
- if (lower(*str1) != lower(*str2))
- break;
- else
- str1++, str2++;
- return lower(*str1) - lower(*str2);
- }
-
- /* strcpy converting everything to lower case (arbitrary) to ignore cases */
- char *
- lcase_strcpy(dst, src)
- register char *dst, *src;
- {
- register char *s = dst;
-
- /* "lower" is a macro, don't increment its argument! */
- while (*dst++ = lower(*src))
- src++;
- return s;
- }
-
- /* this strcpy returns number of bytes copied */
- Strcpy(dst, src)
- register char *dst, *src;
- {
- register int n = 0;
- if (!dst || !src)
- return 0;
- while (*dst++ = *src++)
- n++;
- return n;
- }
-
- char *
- savestr(s)
- register char *s;
- {
- register char *p;
-
- if (!s)
- s = "";
- if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
- error("out of memory saving %s", s);
- return NULL;
- }
- return strcpy(p, s);
- }
-
- /* copy a vector of strings into one string -- return the end of the string */
- char *
- argv_to_string(p, argv)
- register char *p, **argv;
- {
- register int i;
- register char *ptr = p;
-
- *p = 0;
- if (!argv[0])
- return "";
- for (i = 0; argv[i]; i++)
- ptr += strlen(sprintf(ptr, "%s ", argv[i]));
- *--ptr = 0; /* get rid of the last space */
- return ptr;
- }
-
- char *
- itoa(n)
- {
- static char buf[10];
- return sprintf(buf, "%d", n);
- }
-
- /*
- * There are two different kinds of sprintf() --those that return char * and
- * those that return int. System-V returns int (the length of the resulting
- * string). BSD has historically returned a pointer to the resulting string
- * instead. Mush was originally written under BSD, so the usage has always
- * been to assume the char * method. Because the system-v method is far more
- * useful, mush should some day change to use that method, but until then,
- * this routine was written to allow all the unix'es to appear the same to
- * the programmer regardless of which sprintf is actually used. The "latest"
- * version of 4.3BSD (as of Fall 1988) has changed its format to go from the
- * historical BSD method to the sys-v method. It is no longer possible to
- * simply #ifdef this routine for sys-v --it is now required to use this
- * routine regardless of which sprintf is notice to your machine. However,
- * if you know your system's sprintf returns a char *, you can remove the
- * define in strings.h
- */
- #include <varargs.h>
- /*VARARGS*/
- /*ARGSUSED*/
- char *
- Sprintf(va_alist)
- va_dcl
- {
- char *buf, *fmt;
- va_list ap;
-
- va_start(ap);
- buf = va_arg(ap, char *);
- fmt = va_arg(ap, char *);
- #ifdef VPRINTF
- (void) vsprintf(buf, fmt, ap);
- #else
- {
- FILE foo;
- foo._cnt = BUFSIZ;
- foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
- foo._flag = _IOWRT+_IOSTRG;
- (void) _doprnt(fmt, ap, &foo);
- *foo._ptr = '\0'; /* plant terminating null character */
- }
- #endif /* VPRINTF */
- va_end(ap);
- return buf;
- }
-
- void
- print_argv(argv)
- char **argv;
- {
- while (*argv)
- if (debug)
- wprint("(%s) ", *argv++);
- else
- wprint("%s ", *argv++);
- wprint("\n");
- }
-
- /*
- * putstring -- put a string into a file. Expand \t's into tabs and \n's
- * into newlines. Append a \n and fflush(fp);
- */
- void
- putstring(p, fp)
- register char *p;
- register FILE *fp;
- {
- for ( ; *p; ++p)
- if (*p != '\\')
- (void) fputc(*p, fp);
- else
- switch(*++p) {
- case 'n': (void) fputc('\n', fp);
- when 't': (void) fputc('\t', fp);
- otherwise: (void) fputc(*p, fp);
- }
- (void) fputc('\n', fp);
- (void) fflush(fp);
- }
-
- #define chtoi(c) ((int)(c) - (int)'0')
-
- /* m_xlate(str) converts strings of chars which contain ascii representations
- * of control characters appearing in str into the literal characters they
- * represent. The usual curses-mode character expansions (\Cx -> control-x)
- * are honored, as are most C escapes. Unrecognized portions are unchanged.
- */
- char *
- m_xlate (str)
- register char *str;
- {
- register char *r, *s, *t;
- int dv, nd;
-
- /*
- * r will receive the new string, s will track the old one,
- * and t will step through escape sequences
- * This allows the translation to be done in place
- */
- r = s = str;
- while (s && *s) {
- if (*s == '\\') {
- t = s + 1;
- /*
- * After each case below, t should point to the character
- * following the escape sequence
- */
- switch(*t) {
- case '\0' :
- /*
- * Hmmm ... a backslash followed by the string
- * terminator. Copy the backslash ONLY.
- */
- *r++ = *s++;
- break;
- case '0' :
- case '1' :
- case '2' :
- case '3' :
- case '4' :
- case '5' :
- case '6' :
- case '7' :
- /*
- * Convert up to 3 octal digits to their ascii value
- */
- dv = chtoi(*t++);
- for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
- if (chtoi(*t) < 8)
- dv = (8 * dv) + chtoi(*t++);
- else
- break;
- if (dv < 256 && dv > 0)
- /* Valid octal number escaped */
- *r++ = (char)dv;
- else
- /* Invalid octal number, so copy unchanged */
- while (s < t)
- *r++ = *s++;
- break;
- case 'b' :
- *r++ = '\b';
- t++;
- break;
- case 'C' :
- t++;
- if (*t == '?')
- *r++ = '\177';
- else if (*t == '~')
- *r++ = '\036';
- else if (*t == '/')
- *r++ = '\037';
- else if (isalpha(*t) || *t > '\132' && *t < '\140')
- *r++ = *t & 037;
- else
- while (s <= t) *r++ = *s++;
- t++;
- break;
- case 'E' :
- *r++ = '\033';
- t++;
- break;
- case 'f' :
- *r++ = '\f';
- t++;
- break;
- case 'n' :
- *r++ = '\n';
- t++;
- break;
- case 'r' :
- *r++ = '\r';
- t++;
- break;
- case 't' :
- *r++ = '\t';
- t++;
- break;
- case '\\' :
- *r++ = *t++;
- break;
- default :
- /*
- * Not recognized, so copy both characters
- */
- *r++ = *s++;
- *r++ = *s++;
- break;
- }
- /*
- * Now make sure s also points to the character after the
- * escape sequence, by comparing to t
- */
- if (t > s)
- s = t;
- } else
- *r++ = *s++;
- }
- *r = '\0';
- return str;
- }
-
- /*
- * Convert control characters to ascii format (reverse effect of m_xlate()).
- */
- char *
- ctrl_strcpy(s_out, s_in, bind_format)
- register char *s_out, *s_in;
- {
- #if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
- extern char *_unctrl[];
- #endif /* !M_XENIX || M_XENIX && !CURSES */
- char *start = s_out;
-
- for (; *s_in; s_in++)
- if (*s_in == '\n')
- *s_out++ = '\\', *s_out++ = 'n';
- else if (*s_in == '\r')
- *s_out++ = '\\', *s_out++ = 'r';
- else if (*s_in == '\t')
- *s_out++ = '\\', *s_out++ = 't';
- else if (*s_in == ESC)
- *s_out++ = '\\', *s_out++ = 'E';
- else if (iscntrl(*s_in)) {
- if (bind_format)
- *s_out++ = '\\', *s_out++ = 'C';
- else
- *s_out++ = '^';
- *s_out++ = _unctrl[*s_in][1];
- } else
- *s_out++ = *s_in;
- *s_out = 0;
- return start;
- }
-